/**
 * 处理 主线程 方法 的 装饰器
 * 某一个类如果继承BaseService类，类中的方法被此装饰器装饰之后，会自动绑定到ipcMain上
 * 并自动生成对应的类型定义
 * @param methodName 绑定ipcMain上的名称
 * @returns
 */

import { MethodDeclaration } from 'typescript'
import { ipcMain } from 'electron'
import * as fs from 'fs'
import * as path from 'path'

// 全局收集器
export interface ServiceMethodInfo {
  className: string
  methodName: string
  ipcMethodName: string
  returnType?: string
  paramTypes?: string[]
}

// 类型信息接口
export interface TypeInfo {
  name: string
  definition: string
}

// 服务实例注册表
const serviceRegistry = new Map<string, any>()

// 方法信息收集器
const collectedMethods: ServiceMethodInfo[] = []

// 类型信息收集器

export default function IpcMainHandle(ipcMethodName: string): MethodDeclaration | any {
  return function (target: any, propertyKey: string | symbol, descriptor: PropertyDescriptor) {
    const originalMethod = descriptor.value
    const className = ipcMethodName.split('-')[0]
    
    // 收集方法信息（包含类型信息）
    const methodInfo = {
      className,
      methodName: propertyKey as string,
      ipcMethodName,
      returnType: extractReturnType(originalMethod),
      paramTypes: extractParamTypes(originalMethod)
    }
    
    // 避免重复收集
    if (!collectedMethods.find(m => 
      m.className === className && 
      m.methodName === methodInfo.methodName && 
      m.ipcMethodName === ipcMethodName
    )) {
      collectedMethods.push(methodInfo)
      console.log(`📝 收集方法: ${className}.${propertyKey as string} -> ${ipcMethodName}`)
    }
    
    // 保存原方法以便后续注册
    descriptor.value.__originalMethod = originalMethod
    descriptor.value.__methodInfo = methodInfo
    descriptor.value.__decorated = true
    
    return descriptor
  } as MethodDecorator
}

/**
 * 注册单个服务的所有装饰器方法到 ipcMain
 */
function registerServiceMethods(serviceInstance: any) {
  const prototype = Object.getPrototypeOf(serviceInstance)
  const propertyNames = Object.getOwnPropertyNames(prototype)
  
  propertyNames.forEach((propertyName) => {
    const descriptor = Object.getOwnPropertyDescriptor(prototype, propertyName)
    if (descriptor && descriptor.value && descriptor.value.__decorated) {
      const methodInfo = descriptor.value.__methodInfo
      const originalMethod = descriptor.value.__originalMethod
      
      // 检查是否已经注册过
      if (ipcMain.listenerCount(methodInfo.ipcMethodName) === 0) {
        // 注册到 ipcMain
        ipcMain.handle(methodInfo.ipcMethodName, async (event, ...args) => {
          try {
            console.log(`🚀 调用方法: ${methodInfo.className}.${methodInfo.methodName}`)
            return await originalMethod.apply(serviceInstance, args)
          } catch (error) {
            console.error(`❌ 方法调用失败: ${methodInfo.className}.${methodInfo.methodName}`, error)
            throw error
          }
        })
        
        console.log(`✅ 注册 IPC 处理器: ${methodInfo.ipcMethodName}`)
      }
    }
  })
}

/**
 * 统一注册所有服务实例的方法
 */
export function registerAllServiceMethods() {
  try {
    // 获取所有已注册的服务实例并注册它们的方法
    serviceRegistry.forEach((serviceInstance, serviceName) => {
      console.log(`🔄 正在注册服务方法: ${serviceName}`)
      registerServiceMethods(serviceInstance)
    })
    
    // 生成类型定义
    generateTypeDefinitions()
    
    console.log(`✅ 所有服务方法注册完成`)
  } catch (error) {
    console.error('❌ 注册服务方法失败:', error)
  }
}

/**
 * 注册服务实例到全局注册表
 */
export function registerServiceInstance(serviceName: string, serviceInstance: any) {
  if (!serviceRegistry.has(serviceName)) {
    serviceRegistry.set(serviceName, serviceInstance)
    console.log(`🏭 注册服务实例: ${serviceName}`)
  }
}

/**
 * 提取返回类型信息
 */
function extractReturnType(method: Function): string {
  const source = method.toString()
  
  // 尝试从方法签名中提取返回类型
  const returnTypeMatch = source.match(/:\s*Promise<([^>]+)>/)
  if (returnTypeMatch) {
    return `Promise<${returnTypeMatch[1]}>`
  }
  
  // 根据方法名推断返回类型
  const methodName = method.name
  if (methodName === 'login') {
    return 'Promise<LoginResult>'
  } else if (methodName === 'logout') {
    return 'Promise<{ success: boolean; message?: string }>'
  } else if (methodName === 'checkAuth') {
    return 'Promise<{ success: boolean; message?: string; userInfo?: UserInfo }>'
  }
  
  // 检查代码中的返回语句
  if (source.includes('LoginResult')) return 'Promise<LoginResult>'
  if (source.includes('UserInfo')) return 'Promise<{ success: boolean; message?: string; userInfo?: UserInfo }>'
  if (source.includes('success:')) return 'Promise<{ success: boolean; message?: string }>'
  
  return 'Promise<any>'
}

/**
 * 提取参数类型信息
 */
function extractParamTypes(method: Function): string[] {
  const source = method.toString()
  
  // 尝试从方法签名中提取参数类型
  const paramMatch = source.match(/\(([^)]*)\)/)
  
  if (!paramMatch) return []
  
  const params = paramMatch[1]
    .split(',')
    .map(p => p.trim())
    .filter(p => p && !p.startsWith('//'))
  
  return params.map(param => {
    // 移除默认值
    const cleanParam = param.split('=')[0].trim()
    
    // 提取类型注解
    if (cleanParam.includes(': string')) return 'string'
    if (cleanParam.includes(': number')) return 'number'
    if (cleanParam.includes(': boolean')) return 'boolean'
    if (cleanParam.includes(': UserInfo')) return 'UserInfo'
    if (cleanParam.includes(': LoginResult')) return 'LoginResult'
    
    // 根据参数名推断类型
    const paramName = cleanParam.split(':')[0].trim()
    if (paramName === 'username' || paramName === 'password' || paramName === 'token') {
      return 'string'
    }
    
    return 'any'
  })
}

/**
 * 自动生成类型定义文件
 */
function generateTypeDefinitions() {
  try {
    // 修复路径：从编译后的 out/main 目录回到源码目录
    const projectRoot = process.cwd()
    const preloadDir = path.join(projectRoot, 'src', 'preload')
    const typeDefPath = path.join(preloadDir, 'index.d.ts')
    
    console.log(`🔧 类型定义文件路径: ${typeDefPath}`)
    
    // 按服务分组
    const serviceGroups = groupMethodsByService(collectedMethods)
    
    // 生成类型定义内容
    let content = `import { ElectronAPI } from '@electron-toolkit/preload'\n\n`
    
    // 生成接口定义
    content += generateCommonTypes()
    content += '\n'
    
    // 生成服务接口
    Object.entries(serviceGroups).forEach(([serviceName, methods]) => {
      content += generateServiceInterface(serviceName, methods)
      content += '\n'
    })
    
    // 生成全局声明
    content += 'declare global {\n'
    content += '  interface Window {\n'
    content += '    electron: ElectronAPI\n'
    content += '    api: unknown\n'
    
    Object.keys(serviceGroups).forEach(serviceName => {
      // 使用原始的服务名称
      content += `    ${serviceName}: ${getServiceInterfaceName(serviceName)}\n`
    })
    
    content += '  }\n'
    content += '}\n'
    
    // 确保目录存在
    if (!fs.existsSync(preloadDir)) {
      fs.mkdirSync(preloadDir, { recursive: true })
    }
    
    // 写入文件
    fs.writeFileSync(typeDefPath, content, 'utf8')
    console.log(`✅ 自动生成类型定义文件: ${typeDefPath}`)
    
  } catch (error) {
    console.error('❌ 生成类型定义失败:', error)
  }
}

/**
 * 按服务分组方法
 */
function groupMethodsByService(methods: ServiceMethodInfo[]): Record<string, ServiceMethodInfo[]> {
  return methods.reduce((groups, method) => {
    if (!groups[method.className]) {
      groups[method.className] = []
    }
    groups[method.className].push(method)
    return groups
  }, {} as Record<string, ServiceMethodInfo[]>)
}

/**
 * 生成通用类型定义
 */
function generateCommonTypes(): string {
  return `// 用户信息接口
interface UserInfo {
  id: number
  username: string
  name: string
  avatar?: string
  role: string
  loginTime: string
}

// 登录结果接口
interface LoginResult {
  success: boolean
  message?: string
  token?: string
  userInfo?: UserInfo
}

// 通用响应接口
interface BaseResponse {
  success: boolean
  message?: string
}
`
}

/**
 * 生成服务接口
 */
function generateServiceInterface(serviceName: string, methods: ServiceMethodInfo[]): string {
  const interfaceName = getServiceInterfaceName(serviceName)
  
  let content = `// ${serviceName} 接口\n`
  content += `interface ${interfaceName} {\n`
  
  methods.forEach(method => {
    const paramStr = generateMethodParameters(method)
    content += `  ${method.methodName}(${paramStr}): ${method.returnType || 'Promise<any>'}\n`
  })
  
  content += '}\n'
  
  return content
}

/**
 * 生成方法参数字符串
 */
function generateMethodParameters(method: ServiceMethodInfo): string {
  if (!method.paramTypes || method.paramTypes.length === 0) {
    return ''
  }
  
  return method.paramTypes.map((type, index) => {
    let paramName = `param${index}`
    
    // 根据方法名和参数位置生成更好的参数名
    if (method.methodName === 'login') {
      paramName = index === 0 ? 'username' : 'password'
    } else if (method.methodName === 'checkAuth') {
      paramName = 'token'
    }
    
    return `${paramName}: ${type}`
  }).join(', ')
}

/**
 * 获取服务接口名称
 */
function getServiceInterfaceName(serviceName: string): string {
  // 首字母大写
  const className = serviceName.charAt(0).toUpperCase() + serviceName.slice(1)
  // 移除Interface后缀（如果有）
  const baseName = className.endsWith('Interface') ? className.slice(0, -9) : className
  return `${baseName}Interface`
}

/**
 * 获取所有收集的方法信息
 */
export function getAllCollectedMethods(): ServiceMethodInfo[] {
  return [...collectedMethods]
}

/**
 * 获取已注册的服务
 */
export function getRegisteredServices(): string[] {
  return Array.from(serviceRegistry.keys())
}

/**
 * 手动触发类型定义生成
 */
export function generateTypesManually() {
  generateTypeDefinitions()
}